package com.renu.jdependencyanalyser.asm;

import com.renu.jdependencyanalyser.core.ProjectInfo;
import com.renu.jdependencyanalyser.data.ProjectDataCenter;
import com.renu.jdependencyanalyser.model.ClassModel;
import com.renu.jdependencyanalyser.model.MethodModel;
import com.renu.jdependencyanalyser.utils.MyAsmUtil;
import com.renu.jdependencyanalyser.utils.MyFileUtil;
import com.renu.jdependencyanalyser.utils.MyProjectUtil;
import org.objectweb.asm.ClassVisitor;
import org.objectweb.asm.FieldVisitor;
import org.objectweb.asm.MethodVisitor;
import org.objectweb.asm.Opcodes;

import java.util.Arrays;
import java.util.Set;
import java.util.stream.Collectors;

public class CustomClassVisitor extends ClassVisitor {
    private ClassModel  classModel;

    private ProjectInfo projectInfo = ProjectDataCenter.projectInfo;
    public CustomClassVisitor(ClassModel  classModel) {
        super(Opcodes.ASM9);
        this.classModel= classModel;
    }

    // 解析 继承和实现的类 （筛掉jdk类）
    @Override
    public void visit(int version, int access, String name, String signature, String superName, String[] interfaces) {
        String extendClsSig = MyFileUtil.convertPathToDot(superName);
        if (!MyProjectUtil.isJDKClassOrBasicType(extendClsSig)) {
            classModel.getTgtClsSig().add(extendClsSig);
            classModel.setExtendClsSig(extendClsSig);
        }
        if (projectInfo.getOuterClassMap().containsKey(extendClsSig)){ // 外部
            classModel.setOuterExtendClsSig(extendClsSig);
            ClassModel tgtClass = projectInfo.getOuterClassMap().get(extendClsSig);
            tgtClass.getSrcClsSig().add(classModel.getClsSig());
            projectInfo.addBorderClass(extendClsSig);
        }else{

            ClassModel tgtClass = projectInfo.getClassModel(extendClsSig);
            if (tgtClass != null)
                tgtClass.getSrcClsSig().add(classModel.getClsSig());

        }
        Set<String> implemntClsSig = Arrays.stream(interfaces).map(a -> MyFileUtil.convertPathToDot(a)).filter(s->!MyProjectUtil.isJDKClassOrBasicType(s)).collect(Collectors.toSet());
        classModel.setImplementClssSig(implemntClsSig);
        for (String s : implemntClsSig) {
            classModel.getSrcClsSig().add(s);
            if (projectInfo.getOuterClassMap().containsKey(s)){
                classModel.getOuterImplementClsSig().add(s);
                ClassModel tgt = projectInfo.getOuterClassMap().get(s);
                tgt.getSrcClsSig().add(classModel.getClsSig());
                projectInfo.addBorderClass(s);
            }else{
                ClassModel tgt = projectInfo.getClassModel(s);
                if (tgt != null)
                    tgt.getSrcClsSig().add(classModel.getClsSig());
            }
        }

    }

    @Override
    public MethodVisitor visitMethod(int access, String name, String descriptor, String signature, String[] exceptions) {

        String classSig = classModel.getClsSig();
        String methodSig = MyAsmUtil.convertToSignature(classSig, name, descriptor);
        MethodModel methodModel = new MethodModel(methodSig);
        methodModel.setAccess(MyAsmUtil.getAccessModifiers(access));
        projectInfo.addMethod(methodModel);
        projectInfo.methodBindClass(methodSig,classSig);
        // 创建 MethodVisitor 来访问方法
        return new CustomMethodVisitor(projectInfo.getMethod(methodSig));
    }


    @Override
    public FieldVisitor visitField(int access, String name, String descriptor, String signature, Object value) {
        String fieldType = MyProjectUtil.type2String(MyAsmUtil.getTypeFromDescriptor(descriptor));
        String classSig = classModel.getClsSig();
        String fieldSig = MyProjectUtil.getFieldSig(classSig,fieldType,name);
        //projectInfo.addField(fieldSig);
        //projectInfo.fieldBindClass(fieldSig,classSig);
        //projectInfo.fieldBindType(fieldSig,fieldType);

        ClassModel filedClass = projectInfo.getClassModel(fieldType);
        if (filedClass == null && !MyProjectUtil.isJDKClassOrBasicType(fieldType)){
            this.classModel.getOuterfield().add(fieldSig);
            ClassModel tgtclass = projectInfo.getOuterClassMap().get(fieldType);
            projectInfo.bindSrcTgtCls(classModel,tgtclass);
            projectInfo.addBorderClass(fieldType);
        }else if (filedClass!= null){
            ClassModel tgtclass = projectInfo.getClassModel(fieldType);
            projectInfo.bindSrcTgtCls(classModel,tgtclass);
        }
        return super.visitField(access,name,descriptor,signature,value);
    }





}
